<!DOCTYPE HTML>
<html lang="zh-CN">


<head>
    <meta charset="utf-8">
    <meta name="keywords" content="序列化-Serializable和Parcelable的简单介绍, 安卓开发猿">
    <meta name="description" content="Android开发技术博客">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="renderer" content="webkit|ie-stand|ie-comp">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <!-- Global site tag (gtag.js) - Google Analytics -->


    <title>序列化-Serializable和Parcelable的简单介绍 | 安卓开发猿</title>
    <link rel="icon" type="image/png" href="/blog/favicon.png">

    <link rel="stylesheet" type="text/css" href="/blog/libs/awesome/css/all.css">
    <link rel="stylesheet" type="text/css" href="/blog/libs/materialize/materialize.min.css">
    <link rel="stylesheet" type="text/css" href="/blog/libs/aos/aos.css">
    <link rel="stylesheet" type="text/css" href="/blog/libs/animate/animate.min.css">
    <link rel="stylesheet" type="text/css" href="/blog/libs/lightGallery/css/lightgallery.min.css">
    <link rel="stylesheet" type="text/css" href="/blog/css/matery.css">
    <link rel="stylesheet" type="text/css" href="/blog/css/my.css">

    <script src="/blog/libs/jquery/jquery.min.js"></script>
    <script src="https://sdk.jinrishici.com/v2/browser/jinrishici.js" charset="utf-8"></script>
<meta name="generator" content="Hexo 5.4.0"><link rel="alternate" href="/blog/atom.xml" title="安卓开发猿" type="application/atom+xml">
</head>




<body>
    <header class="navbar-fixed">
    <nav id="headNav" class="bg-color nav-transparent">
        <div id="navContainer" class="nav-wrapper container">
            <div class="brand-logo">
                <a href="/blog/" class="waves-effect waves-light">
                    
                    <img src="/blog/medias/logo.png" class="logo-img" alt="LOGO">
                    
                    <span class="logo-span">安卓开发猿</span>
                </a>
            </div>
            

<a href="#" data-target="mobile-nav" class="sidenav-trigger button-collapse"><i class="fas fa-bars"></i></a>
<ul class="right nav-menu">
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="https://xiayunquan.gitee.io/blog/" class="waves-effect waves-light">
      
      <i class="fas fa-home" style="zoom: 0.6;"></i>
      
      <span>首页</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/blog/tags" class="waves-effect waves-light">
      
      <i class="fas fa-tags" style="zoom: 0.6;"></i>
      
      <span>标签</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/blog/categories" class="waves-effect waves-light">
      
      <i class="fas fa-bookmark" style="zoom: 0.6;"></i>
      
      <span>分类</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/blog/archives" class="waves-effect waves-light">
      
      <i class="fas fa-archive" style="zoom: 0.6;"></i>
      
      <span>归档</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/blog/tools" class="waves-effect waves-light">
      
      <i class="fas fa-list" style="zoom: 0.6;"></i>
      
      <span>在线工具箱</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/blog/about" class="waves-effect waves-light">
      
      <i class="fas fa-user-circle" style="zoom: 0.6;"></i>
      
      <span>关于</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/blog/friends" class="waves-effect waves-light">
      
      <i class="fas fa-address-book" style="zoom: 0.6;"></i>
      
      <span>友情链接</span>
    </a>
    
  </li>
  
  <li>
    <a href="#searchModal" class="modal-trigger waves-effect waves-light">
      <i id="searchIcon" class="fas fa-search" title="搜索" style="zoom: 0.85;"></i>
    </a>
  </li>
</ul>


<div id="mobile-nav" class="side-nav sidenav">

    <div class="mobile-head bg-color">
        
        <img src="/blog/medias/logo.png" class="logo-img circle responsive-img">
        
        <div class="logo-name">安卓开发猿</div>
        <div class="logo-desc">
            
            Android开发技术博客
            
        </div>
    </div>

    

    <ul class="menu-list mobile-menu-list">
        
        <li class="m-nav-item">
	  
		<a href="https://xiayunquan.gitee.io/blog/" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-home"></i>
			
			首页
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/blog/tags" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-tags"></i>
			
			标签
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/blog/categories" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-bookmark"></i>
			
			分类
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/blog/archives" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-archive"></i>
			
			归档
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/blog/tools" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-list"></i>
			
			Tools
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/blog/about" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-user-circle"></i>
			
			关于
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/blog/friends" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-address-book"></i>
			
			友情链接
		</a>
          
        </li>
        
        
    </ul>
</div>


        </div>

        
    </nav>

</header>

    



<div class="bg-cover pd-header post-cover" style="background-image: url('/blog/medias/featureimages/3.jpg')">
    <div class="container" style="right: 0px;left: 0px;">
        <div class="row">
            <div class="col s12 m12 l12">
                <div class="brand">
                    <h1 class="description center-align post-title">序列化-Serializable和Parcelable的简单介绍</h1>
                </div>
            </div>
        </div>
    </div>
</div>




<main class="post-container content">

    
    <link rel="stylesheet" href="/blog/libs/tocbot/tocbot.css">
<style>
    #articleContent h1::before,
    #articleContent h2::before,
    #articleContent h3::before,
    #articleContent h4::before,
    #articleContent h5::before,
    #articleContent h6::before {
        display: block;
        content: " ";
        height: 100px;
        margin-top: -100px;
        visibility: hidden;
    }

    #articleContent :focus {
        outline: none;
    }

    .toc-fixed {
        position: fixed;
        top: 64px;
    }

    .toc-widget {
        width: 345px;
        padding-left: 20px;
    }

    .toc-widget .toc-title {
        padding: 35px 0 15px 17px;
        font-size: 1.5rem;
        font-weight: bold;
        line-height: 1.5rem;
    }

    .toc-widget ol {
        padding: 0;
        list-style: none;
    }

    #toc-content {
        padding-bottom: 30px;
        overflow: auto;
    }

    #toc-content ol {
        padding-left: 10px;
    }

    #toc-content ol li {
        padding-left: 10px;
    }

    #toc-content .toc-link:hover {
        color: #42b983;
        font-weight: 700;
        text-decoration: underline;
    }

    #toc-content .toc-link::before {
        background-color: transparent;
        max-height: 25px;

        position: absolute;
        right: 23.5vw;
        display: block;
    }

    #toc-content .is-active-link {
        color: #42b983;
    }

    #floating-toc-btn {
        position: fixed;
        right: 15px;
        bottom: 76px;
        padding-top: 15px;
        margin-bottom: 0;
        z-index: 998;
    }

    #floating-toc-btn .btn-floating {
        width: 48px;
        height: 48px;
    }

    #floating-toc-btn .btn-floating i {
        line-height: 48px;
        font-size: 1.4rem;
    }
</style>
<div class="row">
    <div id="main-content" class="col s12 m12 l9">
        <!-- 文章内容详情 -->
<div id="artDetail">
    <div class="card">
        <div class="card-content article-info">
            <div class="row tag-cate">
                <div class="col s7">
                    
                    <div class="article-tag">
                        
                            <a href="/blog/tags/%E5%BA%8F%E5%88%97%E5%8C%96/">
                                <span class="chip bg-color">序列化</span>
                            </a>
                        
                    </div>
                    
                </div>
                <div class="col s5 right-align">
                    
                    <div class="post-cate">
                        <i class="fas fa-bookmark fa-fw icon-category"></i>
                        
                            <a href="/blog/categories/Java/" class="post-category">
                                Java
                            </a>
                        
                    </div>
                    
                </div>
            </div>

            <div class="post-info">
                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-minus fa-fw"></i>发布日期:&nbsp;&nbsp;
                    2021-09-24
                </div>
                

                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-check fa-fw"></i>更新日期:&nbsp;&nbsp;
                    2023-02-21
                </div>
                

                
                <div class="info-break-policy">
                    <i class="far fa-file-word fa-fw"></i>文章字数:&nbsp;&nbsp;
                    5.1k
                </div>
                

                
                <div class="info-break-policy">
                    <i class="far fa-clock fa-fw"></i>阅读时长:&nbsp;&nbsp;
                    28 分
                </div>
                

                
                    <div id="busuanzi_container_page_pv" class="info-break-policy">
                        <i class="far fa-eye fa-fw"></i>阅读次数:&nbsp;&nbsp;
                        <span id="busuanzi_value_page_pv"></span>
                    </div>
				
            </div>
        </div>
        <hr class="clearfix">

        
        <!-- 是否加载使用自带的 prismjs. -->
        <link rel="stylesheet" href="/blog/libs/prism/prism.css">
        

        

        <div class="card-content article-card-content">
            <div id="articleContent">
                <h1 id="序列化的本质"><a href="#序列化的本质" class="headerlink" title="序列化的本质"></a>序列化的本质</h1><p>序列化是一种用来处理对象流的机制。序列化是为了解决在对对象流进行读写操作时所引发的问题。</p>
<p>序列化：将java对象转换成字节序列的过程，字节码可以保存到数据库、内存、文件等，也可用于网络传输</p>
<p>反序列化：将字节序列恢复为java对象的过程。</p>
<p>序列化实现的方式有很多方案，在java中是使用的JDK内置的Serializable接口来实现序列化，而Android SDK中增加Parcelable方式来实现序列化，除了常见的这2种还有很多其他优秀的序列化和反序列化方案（Twitter的Serial、Google的Protocol Buffers和flatbuffers等），这里先了解一下Serializable和Parcelable2种方式的原理和区别。</p>
<h1 id="Serializable"><a href="#Serializable" class="headerlink" title="Serializable"></a>Serializable</h1><p>Serializable是一个空的标记接口，没有任何方法和属性，implement Serializable只用于标记该对象是可以序列化的。如果一个类implement Serializable，则子类也是可以序列化的。</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * Serializability of a class is enabled by the class implementing the
 * java.io.Serializable interface. Classes that do not implement this
 * interface will not have any of their state serialized or
 * deserialized.  All subtypes of a serializable class are themselves
 * serializable.  The serialization interface has no methods or fields
 * and serves only to identify the semantics of being serializable. &lt;p>
 *
 * To allow subtypes of non-serializable classes to be serialized, the
 * subtype may assume responsibility for saving and restoring the
 * state of the supertype's public, protected, and (if accessible)
 * package fields.  The subtype may assume this responsibility only if
 * the class it extends has an accessible no-arg constructor to
 * initialize the class's state.  It is an error to declare a class
 * Serializable if this is not the case.  The error will be detected at
 * runtime. &lt;p>
 *
 * During deserialization, the fields of non-serializable classes will
 * be initialized using the public or protected no-arg constructor of
 * the class.  A no-arg constructor must be accessible to the subclass
 * that is serializable.  The fields of serializable subclasses will
 * be restored from the stream. &lt;p>
 *
 * When traversing a graph, an object may be encountered that does not
 * support the Serializable interface. In this case the
 * NotSerializableException will be thrown and will identify the class
 * of the non-serializable object. &lt;p>
 *
 * Classes that require special handling during the serialization and
 * deserialization process must implement special methods with these exact
 * signatures:
 *
 * &lt;PRE>
 * private void writeObject(java.io.ObjectOutputStream out)
 *     throws IOException
 * private void readObject(java.io.ObjectInputStream in)
 *     throws IOException, ClassNotFoundException;
 * private void readObjectNoData()
 *     throws ObjectStreamException;
 * &lt;/PRE>
 *
 * &lt;p>The writeObject method is responsible for writing the state of the
 * object for its particular class so that the corresponding
 * readObject method can restore it.  The default mechanism for saving
 * the Object's fields can be invoked by calling
 * out.defaultWriteObject. The method does not need to concern
 * itself with the state belonging to its superclasses or subclasses.
 * State is saved by writing the individual fields to the
 * ObjectOutputStream using the writeObject method or by using the
 * methods for primitive data types supported by DataOutput.
 *
 * &lt;p>The readObject method is responsible for reading from the stream and
 * restoring the classes fields. It may call in.defaultReadObject to invoke
 * the default mechanism for restoring the object's non-static and
 * non-transient fields.  The defaultReadObject method uses information in
 * the stream to assign the fields of the object saved in the stream with the
 * correspondingly named fields in the current object.  This handles the case
 * when the class has evolved to add new fields. The method does not need to
 * concern itself with the state belonging to its superclasses or subclasses.
 * State is saved by writing the individual fields to the
 * ObjectOutputStream using the writeObject method or by using the
 * methods for primitive data types supported by DataOutput.
 *
 * &lt;p>The readObjectNoData method is responsible for initializing the state of
 * the object for its particular class in the event that the serialization
 * stream does not list the given class as a superclass of the object being
 * deserialized.  This may occur in cases where the receiving party uses a
 * different version of the deserialized instance's class than the sending
 * party, and the receiver's version extends classes that are not extended by
 * the sender's version.  This may also occur if the serialization stream has
 * been tampered; hence, readObjectNoData is useful for initializing
 * deserialized objects properly despite a "hostile" or incomplete source
 * stream.
 *
 * &lt;p>Serializable classes that need to designate an alternative object to be
 * used when writing an object to the stream should implement this
 * special method with the exact signature:
 *
 * &lt;PRE>
 * ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
 * &lt;/PRE>&lt;p>
 *
 * This writeReplace method is invoked by serialization if the method
 * exists and it would be accessible from a method defined within the
 * class of the object being serialized. Thus, the method can have private,
 * protected and package-private access. Subclass access to this method
 * follows java accessibility rules. &lt;p>
 *
 * Classes that need to designate a replacement when an instance of it
 * is read from the stream should implement this special method with the
 * exact signature.
 *
 * &lt;PRE>
 * ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
 * &lt;/PRE>&lt;p>
 *
 * This readResolve method follows the same invocation rules and
 * accessibility rules as writeReplace.&lt;p>
 *
 * The serialization runtime associates with each serializable class a version
 * number, called a serialVersionUID, which is used during deserialization to
 * verify that the sender and receiver of a serialized object have loaded
 * classes for that object that are compatible with respect to serialization.
 * If the receiver has loaded a class for the object that has a different
 * serialVersionUID than that of the corresponding sender's class, then
 * deserialization will result in an &#123;@link InvalidClassException&#125;.  A
 * serializable class can declare its own serialVersionUID explicitly by
 * declaring a field named &lt;code>"serialVersionUID"&lt;/code> that must be static,
 * final, and of type &lt;code>long&lt;/code>:
 *
 * &lt;PRE>
 * ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
 * &lt;/PRE>
 *
 * If a serializable class does not explicitly declare a serialVersionUID, then
 * the serialization runtime will calculate a default serialVersionUID value
 * for that class based on various aspects of the class, as described in the
 * Java(TM) Object Serialization Specification.  However, it is &lt;em>strongly
 * recommended&lt;/em> that all serializable classes explicitly declare
 * serialVersionUID values, since the default serialVersionUID computation is
 * highly sensitive to class details that may vary depending on compiler
 * implementations, and can thus result in unexpected
 * &lt;code>InvalidClassException&lt;/code>s during deserialization.  Therefore, to
 * guarantee a consistent serialVersionUID value across different java compiler
 * implementations, a serializable class must declare an explicit
 * serialVersionUID value.  It is also strongly advised that explicit
 * serialVersionUID declarations use the &lt;code>private&lt;/code> modifier where
 * possible, since such declarations apply only to the immediately declaring
 * class--serialVersionUID fields are not useful as inherited members. Array
 * classes cannot declare an explicit serialVersionUID, so they always have
 * the default computed value, but the requirement for matching
 * serialVersionUID values is waived for array classes.
 *
 * Android implementation of serialVersionUID computation will change slightly
 * for some classes if you're targeting android N. In order to preserve compatibility,
 * this change is only enabled is the application target SDK version is set to
 * 24 or higher. It is highly recommended to use an explicit serialVersionUID
 * field to avoid compatibility issues.
 *
 * &lt;h3>Implement Serializable Judiciously&lt;/h3>
 * Refer to &lt;i>Effective Java&lt;/i>'s chapter on serialization for thorough
 * coverage of the serialization API. The book explains how to use this
 * interface without harming your application's maintainability.
 *
 * &lt;h3>Recommended Alternatives&lt;/h3>
 * &lt;strong>JSON&lt;/strong> is concise, human-readable and efficient. Android
 * includes both a &#123;@link android.util.JsonReader streaming API&#125; and a &#123;@link
 * org.json.JSONObject tree API&#125; to read and write JSON. Use a binding library
 * like &lt;a href="http://code.google.com/p/google-gson/">GSON&lt;/a> to read and
 * write Java objects directly.
 *
 * @author  unascribed
 * @see java.io.ObjectOutputStream
 * @see java.io.ObjectInputStream
 * @see java.io.ObjectOutput
 * @see java.io.ObjectInput
 * @see java.io.Externalizable
 * @since   JDK1.1
 */</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">Serializable</span> <span class="token punctuation">&#123;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>上面就是Serializable接口，可以看到注释特别长，总结一下大致如下：</p>
<ol>
<li>Serializable接口没有方法和属性字段，用于标记类可以序列化。</li>
<li>父类可序列化，则子类也可序列化。</li>
<li>static或用transient关键字标记的字段不会被序列化</li>
<li>Serializable内部是使用的ObjectOutputStream和ObjectInputStream来序列化和反序列化的，序列化时通过ObjectOutputStream的writeObject写入对象序列化流数据及状态，默认的保存机制是调用out.defaultWriteObject；反序列化时使用ObjectInputStream.readObject方法将流数据还原成类对象。</li>
<li>序列化运行时是通过serialVersionUID来判断版本的一致性，我们可以在要序列化的类中显式的声明一个static final long serialVerisonUID值，默认情况下java编译器会自动给我们生成一个serialVersionUID，但由于不同的java编译器可能生成的serialVersionUID不同，反序列化期间可能导致InvalidClassException，所以强烈建议我们自己定义serialVersionUID值。</li>
<li>Serializable在使用是会产生大量临时变量，频繁GC，使用了反射，序列化过程较慢，所以官方推荐使用简洁高效的JSON代替Serializable。</li>
</ol>
<h3 id="序列化过程"><a href="#序列化过程" class="headerlink" title="序列化过程"></a>序列化过程</h3><p>下面看看ObjectOutputStream的writeObject相关的源码，简单看看序列化的过程</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * 外部调用，序列化入口
 */</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">writeObject</span><span class="token punctuation">(</span><span class="token class-name">Object</span> obj<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">&#123;</span>
	<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
	<span class="token function">writeObject0</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">&#125;</span>

<span class="token comment">/**
 * 写数据，unshared=false
 */</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">writeObject0</span><span class="token punctuation">(</span><span class="token class-name">Object</span> obj<span class="token punctuation">,</span> <span class="token keyword">boolean</span> unshared<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">&#123;</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token comment">//判断序列化对象的类型</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>obj <span class="token keyword">instanceof</span> <span class="token class-name">Class</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token function">writeClass</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token punctuation">)</span> obj<span class="token punctuation">,</span> unshared<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>obj <span class="token keyword">instanceof</span> <span class="token class-name">ObjectStreamClass</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token function">writeClassDesc</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">ObjectStreamClass</span><span class="token punctuation">)</span> obj<span class="token punctuation">,</span> unshared<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// END Android-changed:  Make Class and ObjectStreamClass replaceable.</span>
    <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>obj <span class="token keyword">instanceof</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token function">writeString</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span> obj<span class="token punctuation">,</span> unshared<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>cl<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token function">writeArray</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> desc<span class="token punctuation">,</span> unshared<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>obj <span class="token keyword">instanceof</span> <span class="token class-name">Enum</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token function">writeEnum</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">Enum</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span><span class="token punctuation">)</span> obj<span class="token punctuation">,</span> desc<span class="token punctuation">,</span> unshared<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>obj <span class="token keyword">instanceof</span> <span class="token class-name">Serializable</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
      	<span class="token comment">//如果是可序列化的，开始写入数据</span>
        <span class="token function">writeOrdinaryObject</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> desc<span class="token punctuation">,</span> unshared<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>
      	<span class="token comment">//不可序列化，抛出异常</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>extendedDebugInfo<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">NotSerializableException</span><span class="token punctuation">(</span>
                cl<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"\n"</span> <span class="token operator">+</span> debugInfoStack<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>
            <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">NotSerializableException</span><span class="token punctuation">(</span>cl<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">&#125;</span>

<span class="token comment">/**
 * 写object数据
 */</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">writeOrdinaryObject</span><span class="token punctuation">(</span><span class="token class-name">Object</span> obj<span class="token punctuation">,</span> <span class="token class-name">ObjectStreamClass</span> desc<span class="token punctuation">,</span> <span class="token keyword">boolean</span> unshared<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>extendedDebugInfo<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        debugInfoStack<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>
            <span class="token punctuation">(</span>depth <span class="token operator">==</span> <span class="token number">1</span> <span class="token operator">?</span> <span class="token string">"root "</span> <span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"object (class \""</span> <span class="token operator">+</span>
            obj<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"\", "</span> <span class="token operator">+</span> obj<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">")"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
    <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
        desc<span class="token punctuation">.</span><span class="token function">checkSerialize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      	<span class="token comment">//写入标记类型，读的时候根据这个来判断</span>
        bout<span class="token punctuation">.</span><span class="token function">writeByte</span><span class="token punctuation">(</span>TC_OBJECT<span class="token punctuation">)</span><span class="token punctuation">;</span>
      	<span class="token comment">//写入类的描述信息</span>
        <span class="token function">writeClassDesc</span><span class="token punctuation">(</span>desc<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        handles<span class="token punctuation">.</span><span class="token function">assign</span><span class="token punctuation">(</span>unshared <span class="token operator">?</span> <span class="token keyword">null</span> <span class="token operator">:</span> obj<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>desc<span class="token punctuation">.</span><span class="token function">isExternalizable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>desc<span class="token punctuation">.</span><span class="token function">isProxy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
          	<span class="token comment">//如果是实现了Externalizable接口，则写入ExternalData(</span>
            <span class="token function">writeExternalData</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">Externalizable</span><span class="token punctuation">)</span> obj<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>
          	<span class="token comment">//写序列化数据</span>
            <span class="token function">writeSerialData</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> desc<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span> <span class="token keyword">finally</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>extendedDebugInfo<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            debugInfoStack<span class="token punctuation">.</span><span class="token function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>

<span class="token comment">/**
 * 真正写object data的入口
 */</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">writeSerialData</span><span class="token punctuation">(</span><span class="token class-name">Object</span> obj<span class="token punctuation">,</span> <span class="token class-name">ObjectStreamClass</span> desc<span class="token punctuation">)</span>
        <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">&#123;</span>
    <span class="token class-name">ObjectStreamClass<span class="token punctuation">.</span>ClassDataSlot</span><span class="token punctuation">[</span><span class="token punctuation">]</span> slots <span class="token operator">=</span> desc<span class="token punctuation">.</span><span class="token function">getClassDataLayout</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  	<span class="token comment">//遍历父类和自己，for循环从父类开始写入数据</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> slots<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">ObjectStreamClass</span> slotDesc <span class="token operator">=</span> slots<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>desc<span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>slotDesc<span class="token punctuation">.</span><span class="token function">hasWriteObjectMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            <span class="token class-name">PutFieldImpl</span> oldPut <span class="token operator">=</span> curPut<span class="token punctuation">;</span>
            curPut <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
            <span class="token class-name">SerialCallbackContext</span> oldContext <span class="token operator">=</span> curContext<span class="token punctuation">;</span>

            <span class="token keyword">if</span> <span class="token punctuation">(</span>extendedDebugInfo<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                debugInfoStack<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>
                    <span class="token string">"custom writeObject data (class \""</span> <span class="token operator">+</span>
                    slotDesc<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"\")"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span>
            <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
                curContext <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SerialCallbackContext</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> slotDesc<span class="token punctuation">)</span><span class="token punctuation">;</span>
                bout<span class="token punctuation">.</span><span class="token function">setBlockDataMode</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                slotDesc<span class="token punctuation">.</span><span class="token function">invokeWriteObject</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                bout<span class="token punctuation">.</span><span class="token function">setBlockDataMode</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                bout<span class="token punctuation">.</span><span class="token function">writeByte</span><span class="token punctuation">(</span>TC_ENDBLOCKDATA<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span> <span class="token keyword">finally</span> <span class="token punctuation">&#123;</span>
                curContext<span class="token punctuation">.</span><span class="token function">setUsed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                curContext <span class="token operator">=</span> oldContext<span class="token punctuation">;</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>extendedDebugInfo<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                    debugInfoStack<span class="token punctuation">.</span><span class="token function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span>
            <span class="token punctuation">&#125;</span>

            curPut <span class="token operator">=</span> oldPut<span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>
          	<span class="token comment">//写入字段属性值</span>
            <span class="token function">defaultWriteFields</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> slotDesc<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>

<span class="token comment">/**
 * 写基本数据类型数据
 */</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">defaultWriteFields</span><span class="token punctuation">(</span><span class="token class-name">Object</span> obj<span class="token punctuation">,</span> <span class="token class-name">ObjectStreamClass</span> desc<span class="token punctuation">)</span>
        <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">&#123;</span>
    <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> cl <span class="token operator">=</span> desc<span class="token punctuation">.</span><span class="token function">forClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>cl <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> obj <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>cl<span class="token punctuation">.</span><span class="token function">isInstance</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">ClassCastException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    desc<span class="token punctuation">.</span><span class="token function">checkDefaultSerialize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">int</span> primDataSize <span class="token operator">=</span> desc<span class="token punctuation">.</span><span class="token function">getPrimDataSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>primVals <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> primVals<span class="token punctuation">.</span>length <span class="token operator">&lt;</span> primDataSize<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        primVals <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">byte</span><span class="token punctuation">[</span>primDataSize<span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
    desc<span class="token punctuation">.</span><span class="token function">getPrimFieldValues</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> primVals<span class="token punctuation">)</span><span class="token punctuation">;</span>
    bout<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span>primVals<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> primDataSize<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token class-name">ObjectStreamField</span><span class="token punctuation">[</span><span class="token punctuation">]</span> fields <span class="token operator">=</span> desc<span class="token punctuation">.</span><span class="token function">getFields</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> objVals <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Object</span><span class="token punctuation">[</span>desc<span class="token punctuation">.</span><span class="token function">getNumObjFields</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> numPrimFields <span class="token operator">=</span> fields<span class="token punctuation">.</span>length <span class="token operator">-</span> objVals<span class="token punctuation">.</span>length<span class="token punctuation">;</span>
    desc<span class="token punctuation">.</span><span class="token function">getObjFieldValues</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> objVals<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> objVals<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>extendedDebugInfo<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            debugInfoStack<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>
                <span class="token string">"field (class \""</span> <span class="token operator">+</span> desc<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"\", name: \""</span> <span class="token operator">+</span>
                fields<span class="token punctuation">[</span>numPrimFields <span class="token operator">+</span> i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"\", type: \""</span> <span class="token operator">+</span>
                fields<span class="token punctuation">[</span>numPrimFields <span class="token operator">+</span> i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">getType</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"\")"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
        <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
            <span class="token function">writeObject0</span><span class="token punctuation">(</span>objVals<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span>
                         fields<span class="token punctuation">[</span>numPrimFields <span class="token operator">+</span> i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">isUnshared</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span> <span class="token keyword">finally</span> <span class="token punctuation">&#123;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>extendedDebugInfo<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                debugInfoStack<span class="token punctuation">.</span><span class="token function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<h3 id="反序列化过程"><a href="#反序列化过程" class="headerlink" title="反序列化过程"></a>反序列化过程</h3><p>再看看ObjectInputStream的readObject相关的源码，反序列化的过程</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token class-name">Object</span> <span class="token function">readObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span><span class="token punctuation">,</span> <span class="token class-name">ClassNotFoundException</span> <span class="token punctuation">&#123;</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token class-name">Object</span> obj <span class="token operator">=</span> <span class="token function">readObject0</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">&#125;</span>

<span class="token comment">/**
 * 读object数据
 */</span>
<span class="token keyword">private</span> <span class="token class-name">Object</span> <span class="token function">readObject0</span><span class="token punctuation">(</span><span class="token keyword">boolean</span> unshared<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">&#123;</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token keyword">byte</span> tc<span class="token punctuation">;</span>
    <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>tc <span class="token operator">=</span> bin<span class="token punctuation">.</span><span class="token function">peekByte</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">==</span> TC_RESET<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        bin<span class="token punctuation">.</span><span class="token function">readByte</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">handleReset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    depth<span class="token operator">++</span><span class="token punctuation">;</span>
    <span class="token comment">// Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929</span>
    <span class="token comment">// totalObjectRefs++;</span>
    <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">switch</span> <span class="token punctuation">(</span>tc<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            <span class="token keyword">case</span> TC_NULL<span class="token operator">:</span>
                <span class="token keyword">return</span> <span class="token function">readNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">case</span> TC_REFERENCE<span class="token operator">:</span>
                <span class="token keyword">return</span> <span class="token function">readHandle</span><span class="token punctuation">(</span>unshared<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">case</span> TC_CLASS<span class="token operator">:</span>
                <span class="token keyword">return</span> <span class="token function">readClass</span><span class="token punctuation">(</span>unshared<span class="token punctuation">)</span><span class="token punctuation">;</span>
            
            <span class="token keyword">case</span> TC_CLASSDESC<span class="token operator">:</span>
            <span class="token keyword">case</span> TC_PROXYCLASSDESC<span class="token operator">:</span>
                <span class="token keyword">return</span> <span class="token function">readClassDesc</span><span class="token punctuation">(</span>unshared<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">case</span> TC_STRING<span class="token operator">:</span>
            <span class="token keyword">case</span> TC_LONGSTRING<span class="token operator">:</span>
                <span class="token keyword">return</span> <span class="token function">checkResolve</span><span class="token punctuation">(</span><span class="token function">readString</span><span class="token punctuation">(</span>unshared<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">case</span> TC_ARRAY<span class="token operator">:</span>
                <span class="token keyword">return</span> <span class="token function">checkResolve</span><span class="token punctuation">(</span><span class="token function">readArray</span><span class="token punctuation">(</span>unshared<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">case</span> TC_ENUM<span class="token operator">:</span>
                <span class="token keyword">return</span> <span class="token function">checkResolve</span><span class="token punctuation">(</span><span class="token function">readEnum</span><span class="token punctuation">(</span>unshared<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            
            <span class="token comment">//判断类型如果是object类型，则读取object对象流</span>
            <span class="token keyword">case</span> TC_OBJECT<span class="token operator">:</span>
                <span class="token keyword">return</span> <span class="token function">checkResolve</span><span class="token punctuation">(</span><span class="token function">readOrdinaryObject</span><span class="token punctuation">(</span>unshared<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">case</span> TC_EXCEPTION<span class="token operator">:</span>
                <span class="token class-name">IOException</span> ex <span class="token operator">=</span> <span class="token function">readFatalException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">WriteAbortedException</span><span class="token punctuation">(</span><span class="token string">"writing aborted"</span><span class="token punctuation">,</span> ex<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">case</span> TC_BLOCKDATA<span class="token operator">:</span>
            <span class="token keyword">case</span> TC_BLOCKDATALONG<span class="token operator">:</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>oldMode<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                    bin<span class="token punctuation">.</span><span class="token function">setBlockDataMode</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    bin<span class="token punctuation">.</span><span class="token function">peek</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>             <span class="token comment">// force header read</span>
                    <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">OptionalDataException</span><span class="token punctuation">(</span>
                        bin<span class="token punctuation">.</span><span class="token function">currentBlockRemaining</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>
                    <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">StreamCorruptedException</span><span class="token punctuation">(</span>
                        <span class="token string">"unexpected block data"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span>

            <span class="token keyword">case</span> TC_ENDBLOCKDATA<span class="token operator">:</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>oldMode<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                    <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">OptionalDataException</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>
                    <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">StreamCorruptedException</span><span class="token punctuation">(</span>
                        <span class="token string">"unexpected end of block data"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span>

            <span class="token keyword">default</span><span class="token operator">:</span>
                <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">StreamCorruptedException</span><span class="token punctuation">(</span>
                    <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"invalid type code: %02X"</span><span class="token punctuation">,</span> tc<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span> <span class="token keyword">finally</span> <span class="token punctuation">&#123;</span>
        depth<span class="token operator">--</span><span class="token punctuation">;</span>
        bin<span class="token punctuation">.</span><span class="token function">setBlockDataMode</span><span class="token punctuation">(</span>oldMode<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>

<span class="token comment">/**
 * 读取流数据
 */</span>
<span class="token keyword">private</span> <span class="token class-name">Object</span> <span class="token function">readOrdinaryObject</span><span class="token punctuation">(</span><span class="token keyword">boolean</span> unshared<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>bin<span class="token punctuation">.</span><span class="token function">readByte</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> TC_OBJECT<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">InternalError</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token class-name">ObjectStreamClass</span> desc <span class="token operator">=</span> <span class="token function">readClassDesc</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    desc<span class="token punctuation">.</span><span class="token function">checkDeserialize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> cl <span class="token operator">=</span> desc<span class="token punctuation">.</span><span class="token function">forClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>cl <span class="token operator">==</span> <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token keyword">class</span> <span class="token operator">||</span> cl <span class="token operator">==</span> <span class="token class-name">Class</span><span class="token punctuation">.</span><span class="token keyword">class</span>
            <span class="token operator">||</span> cl <span class="token operator">==</span> <span class="token class-name">ObjectStreamClass</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">InvalidClassException</span><span class="token punctuation">(</span><span class="token string">"invalid class descriptor"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token class-name">Object</span> obj<span class="token punctuation">;</span>
    <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
        obj <span class="token operator">=</span> desc<span class="token punctuation">.</span><span class="token function">isInstantiable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">?</span> desc<span class="token punctuation">.</span><span class="token function">newInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">throw</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span><span class="token punctuation">)</span> <span class="token keyword">new</span> <span class="token class-name">InvalidClassException</span><span class="token punctuation">(</span>
            desc<span class="token punctuation">.</span><span class="token function">forClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            <span class="token string">"unable to create instance"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">initCause</span><span class="token punctuation">(</span>ex<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    passHandle <span class="token operator">=</span> handles<span class="token punctuation">.</span><span class="token function">assign</span><span class="token punctuation">(</span>unshared <span class="token operator">?</span> unsharedMarker <span class="token operator">:</span> obj<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">ClassNotFoundException</span> resolveEx <span class="token operator">=</span> desc<span class="token punctuation">.</span><span class="token function">getResolveException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>resolveEx <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        handles<span class="token punctuation">.</span><span class="token function">markException</span><span class="token punctuation">(</span>passHandle<span class="token punctuation">,</span> resolveEx<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>desc<span class="token punctuation">.</span><span class="token function">isExternalizable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
      	<span class="token comment">//读取自定义序列化数据</span>
        <span class="token function">readExternalData</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">Externalizable</span><span class="token punctuation">)</span> obj<span class="token punctuation">,</span> desc<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>
      	<span class="token comment">//读取序列化数据</span>
        <span class="token function">readSerialData</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> desc<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token keyword">return</span> obj<span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span>

<span class="token comment">/**
 * 读取序列化数据
 */</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">readSerialData</span><span class="token punctuation">(</span><span class="token class-name">Object</span> obj<span class="token punctuation">,</span> <span class="token class-name">ObjectStreamClass</span> desc<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">&#123;</span>
    <span class="token class-name">ObjectStreamClass<span class="token punctuation">.</span>ClassDataSlot</span><span class="token punctuation">[</span><span class="token punctuation">]</span> slots <span class="token operator">=</span> desc<span class="token punctuation">.</span><span class="token function">getClassDataLayout</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> slots<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">ObjectStreamClass</span> slotDesc <span class="token operator">=</span> slots<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>desc<span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>slots<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>hasData<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>obj <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> handles<span class="token punctuation">.</span><span class="token function">lookupException</span><span class="token punctuation">(</span>passHandle<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                <span class="token function">defaultReadFields</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> slotDesc<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// skip field values</span>
            <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>slotDesc<span class="token punctuation">.</span><span class="token function">hasReadObjectMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                <span class="token comment">// BEGIN Android-changed: ThreadDeath cannot cause corruption on Android.</span>
                <span class="token comment">// Android does not support Thread.stop() or Thread.stop(Throwable) so this</span>
                <span class="token comment">// does not need to protect against state corruption that can occur when a</span>
                <span class="token comment">// ThreadDeath Error is thrown in the middle of the finally block.</span>
                <span class="token class-name">SerialCallbackContext</span> oldContext <span class="token operator">=</span> curContext<span class="token punctuation">;</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>oldContext <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
                    oldContext<span class="token punctuation">.</span><span class="token function">check</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
                    curContext <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SerialCallbackContext</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> slotDesc<span class="token punctuation">)</span><span class="token punctuation">;</span>

                    bin<span class="token punctuation">.</span><span class="token function">setBlockDataMode</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    slotDesc<span class="token punctuation">.</span><span class="token function">invokeReadObject</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">ClassNotFoundException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                    <span class="token comment">/*
                     * In most cases, the handle table has already
                     * propagated a CNFException to passHandle at this
                     * point; this mark call is included to address cases
                     * where the custom readObject method has cons'ed and
                     * thrown a new CNFException of its own.
                     */</span>
                    handles<span class="token punctuation">.</span><span class="token function">markException</span><span class="token punctuation">(</span>passHandle<span class="token punctuation">,</span> ex<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span> <span class="token keyword">finally</span> <span class="token punctuation">&#123;</span>
                    curContext<span class="token punctuation">.</span><span class="token function">setUsed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token keyword">if</span> <span class="token punctuation">(</span>oldContext<span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
                        oldContext<span class="token punctuation">.</span><span class="token function">check</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    curContext <span class="token operator">=</span> oldContext<span class="token punctuation">;</span>
                    <span class="token comment">// END Android-changed: ThreadDeath cannot cause corruption on Android.</span>
                <span class="token punctuation">&#125;</span>

                <span class="token comment">/*
                 * defaultDataEnd may have been set indirectly by custom
                 * readObject() method when calling defaultReadObject() or
                 * readFields(); clear it to restore normal read behavior.
                 */</span>
                defaultDataEnd <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>
                <span class="token function">defaultReadFields</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> slotDesc<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span>

            <span class="token keyword">if</span> <span class="token punctuation">(</span>slotDesc<span class="token punctuation">.</span><span class="token function">hasWriteObjectData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                <span class="token function">skipCustomData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>
                bin<span class="token punctuation">.</span><span class="token function">setBlockDataMode</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span>
        <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>obj <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span>
                slotDesc<span class="token punctuation">.</span><span class="token function">hasReadObjectNoDataMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
                handles<span class="token punctuation">.</span><span class="token function">lookupException</span><span class="token punctuation">(</span>passHandle<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
            <span class="token punctuation">&#123;</span>
                slotDesc<span class="token punctuation">.</span><span class="token function">invokeReadObjectNoData</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>

<span class="token comment">/**
 * 读取字段属性数据
 */</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">defaultReadFields</span><span class="token punctuation">(</span><span class="token class-name">Object</span> obj<span class="token punctuation">,</span> <span class="token class-name">ObjectStreamClass</span> desc<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">&#123;</span>
    <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> cl <span class="token operator">=</span> desc<span class="token punctuation">.</span><span class="token function">forClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>cl <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> obj <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>cl<span class="token punctuation">.</span><span class="token function">isInstance</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">ClassCastException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token keyword">int</span> primDataSize <span class="token operator">=</span> desc<span class="token punctuation">.</span><span class="token function">getPrimDataSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>primVals <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> primVals<span class="token punctuation">.</span>length <span class="token operator">&lt;</span> primDataSize<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        primVals <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">byte</span><span class="token punctuation">[</span>primDataSize<span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
        bin<span class="token punctuation">.</span><span class="token function">readFully</span><span class="token punctuation">(</span>primVals<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> primDataSize<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>obj <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        desc<span class="token punctuation">.</span><span class="token function">setPrimFieldValues</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> primVals<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token keyword">int</span> objHandle <span class="token operator">=</span> passHandle<span class="token punctuation">;</span>
    <span class="token class-name">ObjectStreamField</span><span class="token punctuation">[</span><span class="token punctuation">]</span> fields <span class="token operator">=</span> desc<span class="token punctuation">.</span><span class="token function">getFields</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> objVals <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Object</span><span class="token punctuation">[</span>desc<span class="token punctuation">.</span><span class="token function">getNumObjFields</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> numPrimFields <span class="token operator">=</span> fields<span class="token punctuation">.</span>length <span class="token operator">-</span> objVals<span class="token punctuation">.</span>length<span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> objVals<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">ObjectStreamField</span> f <span class="token operator">=</span> fields<span class="token punctuation">[</span>numPrimFields <span class="token operator">+</span> i<span class="token punctuation">]</span><span class="token punctuation">;</span>
        objVals<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">readObject0</span><span class="token punctuation">(</span>f<span class="token punctuation">.</span><span class="token function">isUnshared</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>f<span class="token punctuation">.</span><span class="token function">getField</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            handles<span class="token punctuation">.</span><span class="token function">markDependency</span><span class="token punctuation">(</span>objHandle<span class="token punctuation">,</span> passHandle<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>obj <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        desc<span class="token punctuation">.</span><span class="token function">setObjFieldValues</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> objVals<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
    passHandle <span class="token operator">=</span> objHandle<span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>可以看到ObjectInputStream反序列化和ObjectOutputStream方法是一一对应，怎么写就怎么读取，其实java io API内部设计都是这样，所有的Input和Output，Reader和Writer方法基本都是一一对应，掌握了输出流就知道输入流对应该怎么写。</p>
<h3 id="Externalizable"><a href="#Externalizable" class="headerlink" title="Externalizable"></a>Externalizable</h3><p>从上面的源码中可以看到有一个这个判断：</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">//ObjectOutputStream</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>desc<span class="token punctuation">.</span><span class="token function">isExternalizable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>desc<span class="token punctuation">.</span><span class="token function">isProxy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
	<span class="token function">writeExternalData</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">Externalizable</span><span class="token punctuation">)</span> obj<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span> 

<span class="token comment">//ObjectInputStream</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>desc<span class="token punctuation">.</span><span class="token function">isExternalizable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
	<span class="token function">readExternalData</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">Externalizable</span><span class="token punctuation">)</span> obj<span class="token punctuation">,</span> desc<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>Serializable有一个直接子类Externalizable接口，该接口有两个方法<code>writeExternal(ObjectOutput out)</code>、<code>readExternal(ObjectInput in)</code>，可以使用该接口来实现自定义序列化细节。看下源码</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java">
<span class="token comment">/**
 * Only the identity of the class of an Externalizable instance is
 * written in the serialization stream and it is the responsibility
 * of the class to save and restore the contents of its instances.
 *
 * The writeExternal and readExternal methods of the Externalizable
 * interface are implemented by a class to give the class complete
 * control over the format and contents of the stream for an object
 * and its supertypes. These methods must explicitly
 * coordinate with the supertype to save its state. These methods supersede
 * customized implementations of writeObject and readObject methods.&lt;br>
 *
 * Object Serialization uses the Serializable and Externalizable
 * interfaces.  Object persistence mechanisms can use them as well.  Each
 * object to be stored is tested for the Externalizable interface. If
 * the object supports Externalizable, the writeExternal method is called. If the
 * object does not support Externalizable and does implement
 * Serializable, the object is saved using
 * ObjectOutputStream. &lt;br> When an Externalizable object is
 * reconstructed, an instance is created using the public no-arg
 * constructor, then the readExternal method called.  Serializable
 * objects are restored by reading them from an ObjectInputStream.&lt;br>
 *
 * An Externalizable instance can designate a substitution object via
 * the writeReplace and readResolve methods documented in the Serializable
 * interface.&lt;br>
 *
 * @author  unascribed
 * @see java.io.ObjectOutputStream
 * @see java.io.ObjectInputStream
 * @see java.io.ObjectOutput
 * @see java.io.ObjectInput
 * @see java.io.Serializable
 * @since   JDK1.1
 */</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">Externalizable</span> <span class="token keyword">extends</span> <span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span>Serializable</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">/**
     * The object implements the writeExternal method to save its contents
     * by calling the methods of DataOutput for its primitive values or
     * calling the writeObject method of ObjectOutput for objects, strings,
     * and arrays.
     *
     * @serialData Overriding methods should use this tag to describe
     *             the data layout of this Externalizable object.
     *             List the sequence of element types and, if possible,
     *             relate the element to a public/protected field and/or
     *             method of this Externalizable class.
     *
     * @param out the stream to write the object to
     * @exception IOException Includes any I/O exceptions that may occur
     */</span>
    <span class="token keyword">void</span> <span class="token function">writeExternal</span><span class="token punctuation">(</span><span class="token class-name">ObjectOutput</span> out<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span><span class="token punctuation">;</span>

    <span class="token comment">/**
     * The object implements the readExternal method to restore its
     * contents by calling the methods of DataInput for primitive
     * types and readObject for objects, strings and arrays.  The
     * readExternal method must read the values in the same sequence
     * and with the same types as were written by writeExternal.
     *
     * @param in the stream to read data from in order to restore the object
     * @exception IOException if I/O errors occur
     * @exception ClassNotFoundException If the class for an object being
     *              restored cannot be found.
     */</span>
    <span class="token keyword">void</span> <span class="token function">readExternal</span><span class="token punctuation">(</span><span class="token class-name">ObjectInput</span> in<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span><span class="token punctuation">,</span> <span class="token class-name">ClassNotFoundException</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>看一个示例，android.telephony.mbms.DownloadRequest中的SerializationDataContainer内部类实现了Externalizable接口来自定义序列化内容，代码如下。</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">SerializationDataContainer</span> <span class="token keyword">implements</span> <span class="token class-name">Externalizable</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> fileServiceId<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">Uri</span> source<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">Uri</span> destination<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> subscriptionId<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> appIntent<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> version<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">SerializationDataContainer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span><span class="token punctuation">&#125;</span>

    <span class="token class-name">SerializationDataContainer</span><span class="token punctuation">(</span><span class="token class-name">DownloadRequest</span> request<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        fileServiceId <span class="token operator">=</span> request<span class="token punctuation">.</span>fileServiceId<span class="token punctuation">;</span>
        source <span class="token operator">=</span> request<span class="token punctuation">.</span>sourceUri<span class="token punctuation">;</span>
        destination <span class="token operator">=</span> request<span class="token punctuation">.</span>destinationUri<span class="token punctuation">;</span>
        subscriptionId <span class="token operator">=</span> request<span class="token punctuation">.</span>subscriptionId<span class="token punctuation">;</span>
        appIntent <span class="token operator">=</span> request<span class="token punctuation">.</span>serializedResultIntentForApp<span class="token punctuation">;</span>
        version <span class="token operator">=</span> request<span class="token punctuation">.</span>version<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">writeExternal</span><span class="token punctuation">(</span><span class="token class-name">ObjectOutput</span> objectOutput<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">&#123;</span>
        objectOutput<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span>version<span class="token punctuation">)</span><span class="token punctuation">;</span>
        objectOutput<span class="token punctuation">.</span><span class="token function">writeUTF</span><span class="token punctuation">(</span>fileServiceId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        objectOutput<span class="token punctuation">.</span><span class="token function">writeUTF</span><span class="token punctuation">(</span>source<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        objectOutput<span class="token punctuation">.</span><span class="token function">writeUTF</span><span class="token punctuation">(</span>destination<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        objectOutput<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span>subscriptionId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        objectOutput<span class="token punctuation">.</span><span class="token function">writeUTF</span><span class="token punctuation">(</span>appIntent<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">readExternal</span><span class="token punctuation">(</span><span class="token class-name">ObjectInput</span> objectInput<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">&#123;</span>
        version <span class="token operator">=</span> objectInput<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        fileServiceId <span class="token operator">=</span> objectInput<span class="token punctuation">.</span><span class="token function">readUTF</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        source <span class="token operator">=</span> <span class="token class-name">Uri</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>objectInput<span class="token punctuation">.</span><span class="token function">readUTF</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        destination <span class="token operator">=</span> <span class="token class-name">Uri</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>objectInput<span class="token punctuation">.</span><span class="token function">readUTF</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        subscriptionId <span class="token operator">=</span> objectInput<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        appIntent <span class="token operator">=</span> objectInput<span class="token punctuation">.</span><span class="token function">readUTF</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// Do version checks here -- future versions may have other fields.</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>

<span class="token comment">//写入序列化数据</span>
<span class="token keyword">public</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">toByteArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">ByteArrayOutputStream</span> byteArrayOutputStream <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ByteArrayOutputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">ObjectOutputStream</span> stream <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ObjectOutputStream</span><span class="token punctuation">(</span>byteArrayOutputStream<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">SerializationDataContainer</span> container <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SerializationDataContainer</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        stream<span class="token punctuation">.</span><span class="token function">writeObject</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span>
        stream<span class="token punctuation">.</span><span class="token function">flush</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> byteArrayOutputStream<span class="token punctuation">.</span><span class="token function">toByteArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> e<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token comment">// Really should never happen</span>
        <span class="token class-name">Log</span><span class="token punctuation">.</span><span class="token function">e</span><span class="token punctuation">(</span>LOG_TAG<span class="token punctuation">,</span> <span class="token string">"Got IOException trying to serialize opaque data"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>

<span class="token comment">//还原序列化对象</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">Builder</span> <span class="token function">fromSerializedRequest</span><span class="token punctuation">(</span><span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> data<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token class-name">Builder</span> builder<span class="token punctuation">;</span>
    <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">ObjectInputStream</span> stream <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ObjectInputStream</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ByteArrayInputStream</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">SerializationDataContainer</span> dataContainer <span class="token operator">=</span>
                <span class="token punctuation">(</span><span class="token class-name">SerializationDataContainer</span><span class="token punctuation">)</span> stream<span class="token punctuation">.</span><span class="token function">readObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        builder <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Builder</span><span class="token punctuation">(</span>dataContainer<span class="token punctuation">.</span>source<span class="token punctuation">,</span> dataContainer<span class="token punctuation">.</span>destination<span class="token punctuation">)</span><span class="token punctuation">;</span>
        builder<span class="token punctuation">.</span>version <span class="token operator">=</span> dataContainer<span class="token punctuation">.</span>version<span class="token punctuation">;</span>
        builder<span class="token punctuation">.</span>appIntent <span class="token operator">=</span> dataContainer<span class="token punctuation">.</span>appIntent<span class="token punctuation">;</span>
        builder<span class="token punctuation">.</span>fileServiceId <span class="token operator">=</span> dataContainer<span class="token punctuation">.</span>fileServiceId<span class="token punctuation">;</span>
        builder<span class="token punctuation">.</span>subscriptionId <span class="token operator">=</span> dataContainer<span class="token punctuation">.</span>subscriptionId<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> e<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token comment">// Really should never happen</span>
        <span class="token class-name">Log</span><span class="token punctuation">.</span><span class="token function">e</span><span class="token punctuation">(</span>LOG_TAG<span class="token punctuation">,</span> <span class="token string">"Got IOException trying to parse opaque data"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">ClassNotFoundException</span> e<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">Log</span><span class="token punctuation">.</span><span class="token function">e</span><span class="token punctuation">(</span>LOG_TAG<span class="token punctuation">,</span> <span class="token string">"Got ClassNotFoundException trying to parse opaque data"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
    <span class="token keyword">return</span> builder<span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>到此Serializable了解的差不多了，下面看下Android中的Parcelable实现序列化的一些细节。</p>
<h1 id="Parcelable"><a href="#Parcelable" class="headerlink" title="Parcelable"></a>Parcelable</h1><p>Parcelable是Android中的一种序列化机制，Parcelable的原理是通过Parcel将一个完整的对象进行分解，而分解后的每一部分都是Intent所支持的数据类型，Parcel机制是将序列化的数据写入到一个共享内存当中，其他进程可以通过Parcel从这块共享内存中读出字节流，因此可以实现在Binder中跨进程传输数据，实现传递对象的功能。</p>
<p>看下Parcelable接口的源码</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">android<span class="token punctuation">.</span>os</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">android<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">IntDef</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Retention</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">RetentionPolicy</span><span class="token punctuation">;</span>

<span class="token comment">/**
 * Interface for classes whose instances can be written to
 * and restored from a &#123;@link Parcel&#125;.  Classes implementing the Parcelable
 * interface must also have a non-null static field called &lt;code>CREATOR&lt;/code>
 * of a type that implements the &#123;@link Parcelable.Creator&#125; interface.
 * 
 * &lt;p>A typical implementation of Parcelable is:&lt;/p>
 * 
 * &lt;pre>
 * public class MyParcelable implements Parcelable &#123;
 *     private int mData;
 *
 *     public int describeContents() &#123;
 *         return 0;
 *     &#125;
 *
 *     public void writeToParcel(Parcel out, int flags) &#123;
 *         out.writeInt(mData);
 *     &#125;
 *
 *     public static final Parcelable.Creator&amp;lt;MyParcelable&amp;gt; CREATOR
 *             = new Parcelable.Creator&amp;lt;MyParcelable&amp;gt;() &#123;
 *         public MyParcelable createFromParcel(Parcel in) &#123;
 *             return new MyParcelable(in);
 *         &#125;
 *
 *         public MyParcelable[] newArray(int size) &#123;
 *             return new MyParcelable[size];
 *         &#125;
 *     &#125;;
 *     
 *     private MyParcelable(Parcel in) &#123;
 *         mData = in.readInt();
 *     &#125;
 * &#125;&lt;/pre>
 */</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">Parcelable</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">/** @hide */</span>
    <span class="token annotation punctuation">@IntDef</span><span class="token punctuation">(</span>flag <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> prefix <span class="token operator">=</span> <span class="token punctuation">&#123;</span> <span class="token string">"PARCELABLE_"</span> <span class="token punctuation">&#125;</span><span class="token punctuation">,</span> value <span class="token operator">=</span> <span class="token punctuation">&#123;</span>
            PARCELABLE_WRITE_RETURN_VALUE<span class="token punctuation">,</span>
            PARCELABLE_ELIDE_DUPLICATES<span class="token punctuation">,</span>
    <span class="token punctuation">&#125;</span><span class="token punctuation">)</span>
    <span class="token annotation punctuation">@Retention</span><span class="token punctuation">(</span><span class="token class-name">RetentionPolicy</span><span class="token punctuation">.</span>SOURCE<span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token annotation punctuation">@interface</span> <span class="token class-name">WriteFlags</span> <span class="token punctuation">&#123;</span><span class="token punctuation">&#125;</span>

    <span class="token comment">/**
     * Flag for use with &#123;@link #writeToParcel&#125;: the object being written
     * is a return value, that is the result of a function such as
     * "&lt;code>Parcelable someFunction()&lt;/code>",
     * "&lt;code>void someFunction(out Parcelable)&lt;/code>", or
     * "&lt;code>void someFunction(inout Parcelable)&lt;/code>".  Some implementations
     * may want to release resources at this point.
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> PARCELABLE_WRITE_RETURN_VALUE <span class="token operator">=</span> <span class="token number">0x0001</span><span class="token punctuation">;</span>

    <span class="token comment">/**
     * Flag for use with &#123;@link #writeToParcel&#125;: a parent object will take
     * care of managing duplicate state/data that is nominally replicated
     * across its inner data members.  This flag instructs the inner data
     * types to omit that data during marshaling.  Exact behavior may vary
     * on a case by case basis.
     * @hide
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> PARCELABLE_ELIDE_DUPLICATES <span class="token operator">=</span> <span class="token number">0x0002</span><span class="token punctuation">;</span>

    <span class="token comment">/*
     * Bit masks for use with &#123;@link #describeContents&#125;: each bit represents a
     * kind of object considered to have potential special significance when
     * marshalled.
     */</span>

    <span class="token comment">/** @hide */</span>
    <span class="token annotation punctuation">@IntDef</span><span class="token punctuation">(</span>flag <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> prefix <span class="token operator">=</span> <span class="token punctuation">&#123;</span> <span class="token string">"CONTENTS_"</span> <span class="token punctuation">&#125;</span><span class="token punctuation">,</span> value <span class="token operator">=</span> <span class="token punctuation">&#123;</span>
            CONTENTS_FILE_DESCRIPTOR<span class="token punctuation">,</span>
    <span class="token punctuation">&#125;</span><span class="token punctuation">)</span>
    <span class="token annotation punctuation">@Retention</span><span class="token punctuation">(</span><span class="token class-name">RetentionPolicy</span><span class="token punctuation">.</span>SOURCE<span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token annotation punctuation">@interface</span> <span class="token class-name">ContentsFlags</span> <span class="token punctuation">&#123;</span><span class="token punctuation">&#125;</span>

    <span class="token comment">/**
     * Descriptor bit used with &#123;@link #describeContents()&#125;: indicates that
     * the Parcelable object's flattened representation includes a file descriptor.
     *
     * @see #describeContents()
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> CONTENTS_FILE_DESCRIPTOR <span class="token operator">=</span> <span class="token number">0x0001</span><span class="token punctuation">;</span>
    
    <span class="token comment">/**
     * Describe the kinds of special objects contained in this Parcelable
     * instance's marshaled representation. For example, if the object will
     * include a file descriptor in the output of &#123;@link #writeToParcel(Parcel, int)&#125;,
     * the return value of this method must include the
     * &#123;@link #CONTENTS_FILE_DESCRIPTOR&#125; bit.
     *  
     * @return a bitmask indicating the set of special object types marshaled
     * by this Parcelable object instance.
     */</span>
    <span class="token keyword">public</span> <span class="token annotation punctuation">@ContentsFlags</span> <span class="token keyword">int</span> <span class="token function">describeContents</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    <span class="token comment">/**
     * Flatten this object in to a Parcel.
     * 
     * @param dest The Parcel in which the object should be written.
     * @param flags Additional flags about how the object should be written.
     * May be 0 or &#123;@link #PARCELABLE_WRITE_RETURN_VALUE&#125;.
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">writeToParcel</span><span class="token punctuation">(</span><span class="token class-name">Parcel</span> dest<span class="token punctuation">,</span> <span class="token annotation punctuation">@WriteFlags</span> <span class="token keyword">int</span> flags<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">/**
     * Interface that must be implemented and provided as a public CREATOR
     * field that generates instances of your Parcelable class from a Parcel.
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">Creator</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">></span></span> <span class="token punctuation">&#123;</span>
        <span class="token comment">/**
         * Create a new instance of the Parcelable class, instantiating it
         * from the given Parcel whose data had previously been written by
         * &#123;@link Parcelable#writeToParcel Parcelable.writeToParcel()&#125;.
         * 
         * @param source The Parcel to read the object's data from.
         * @return Returns a new instance of the Parcelable class.
         */</span>
        <span class="token keyword">public</span> <span class="token class-name">T</span> <span class="token function">createFromParcel</span><span class="token punctuation">(</span><span class="token class-name">Parcel</span> source<span class="token punctuation">)</span><span class="token punctuation">;</span>
        
        <span class="token comment">/**
         * Create a new array of the Parcelable class.
         * 
         * @param size Size of the array.
         * @return Returns an array of the Parcelable class, with every entry
         * initialized to null.
         */</span>
        <span class="token keyword">public</span> <span class="token class-name">T</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">newArray</span><span class="token punctuation">(</span><span class="token keyword">int</span> size<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">/**
     * Specialization of &#123;@link Creator&#125; that allows you to receive the
     * ClassLoader the object is being created in.
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">ClassLoaderCreator</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">></span></span> <span class="token keyword">extends</span> <span class="token class-name">Creator</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">></span></span> <span class="token punctuation">&#123;</span>
        <span class="token comment">/**
         * Create a new instance of the Parcelable class, instantiating it
         * from the given Parcel whose data had previously been written by
         * &#123;@link Parcelable#writeToParcel Parcelable.writeToParcel()&#125; and
         * using the given ClassLoader.
         *
         * @param source The Parcel to read the object's data from.
         * @param loader The ClassLoader that this object is being created in.
         * @return Returns a new instance of the Parcelable class.
         */</span>
        <span class="token keyword">public</span> <span class="token class-name">T</span> <span class="token function">createFromParcel</span><span class="token punctuation">(</span><span class="token class-name">Parcel</span> source<span class="token punctuation">,</span> <span class="token class-name">ClassLoader</span> loader<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>使用Parcelable接口实现序列化需要：</p>
<ol>
<li><p>创建一个实现了Parcelable.Creator接口的静态常量，其中createFromParcel方法用于反序列化时创建新的实例。</p>
</li>
<li><p>重写<code>writeToParcel(Parcel out, int flags)</code> 方法通过Parcel将数据写入共享内存，parcel可以写入原始数据类型（如：writeInt()、writeFloat()、writeString()等）、也可以写入一个Parcelable对象<code>writeParcelable(Parcelable p, int parcelableFlags)</code>、还提供了2种写入序列化对象集合的方式<code>writeList(List)</code>、<code>writeTypedList(List)</code></p>
</li>
<li><p>声明一个Parcel参数的构造方法读取Parcel数据</p>
</li>
</ol>
<p>Parcel中的写和读都是native方法，底层采用c语言编写，具体的源码就不去研究了。</p>
<p>在内存上序列化的时候，Parcelable比Serializable性能高，所以尽量使用Parcelable来序列化；但是Parcelable不适合磁盘上的数据持久化，所以这种情况使用Serializable更好。</p>

                
            </div>
            <hr/>

            



            <div class="tag_share" style="display: block;">
                <div class="post-meta__tag-list" style="display: inline-block;">
                    
                        <div class="article-tag">
                            
                                <a href="/blog/tags/%E5%BA%8F%E5%88%97%E5%8C%96/">
                                    <span class="chip bg-color">序列化</span>
                                </a>
                            
                        </div>
                    
                </div>
                <div class="post_share" style="zoom: 80%; width: fit-content; display: inline-block; float: right; margin: -0.15rem 0;">
                    <link rel="stylesheet" type="text/css" href="/blog/libs/share/css/share.min.css">
<div id="article-share">

    
    <div class="social-share" data-sites="wechat,qq,facebook,google,weibo" data-wechat-qrcode-helper="<p>微信扫一扫即可分享！</p>"></div>
    <script src="/blog/libs/share/js/social-share.min.js"></script>
    

    

</div>

                </div>
            </div>
            
                <style>
    #reward {
        margin: 40px 0;
        text-align: center;
    }

    #reward .reward-link {
        font-size: 1.4rem;
        line-height: 38px;
    }

    #reward .btn-floating:hover {
        box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2), 0 5px 15px rgba(0, 0, 0, 0.2);
    }

    #rewardModal {
        width: 320px;
        height: 350px;
    }

    #rewardModal .reward-title {
        margin: 15px auto;
        padding-bottom: 5px;
    }

    #rewardModal .modal-content {
        padding: 10px;
    }

    #rewardModal .close {
        position: absolute;
        right: 15px;
        top: 15px;
        color: rgba(0, 0, 0, 0.5);
        font-size: 1.3rem;
        line-height: 20px;
        cursor: pointer;
    }

    #rewardModal .close:hover {
        color: #ef5350;
        transform: scale(1.3);
        -moz-transform:scale(1.3);
        -webkit-transform:scale(1.3);
        -o-transform:scale(1.3);
    }

    #rewardModal .reward-tabs {
        margin: 0 auto;
        width: 210px;
    }

    .reward-tabs .tabs {
        height: 38px;
        margin: 10px auto;
        padding-left: 0;
    }

    .reward-content ul {
        padding-left: 0 !important;
    }

    .reward-tabs .tabs .tab {
        height: 38px;
        line-height: 38px;
    }

    .reward-tabs .tab a {
        color: #fff;
        background-color: #ccc;
    }

    .reward-tabs .tab a:hover {
        background-color: #ccc;
        color: #fff;
    }

    .reward-tabs .wechat-tab .active {
        color: #fff !important;
        background-color: #22AB38 !important;
    }

    .reward-tabs .alipay-tab .active {
        color: #fff !important;
        background-color: #019FE8 !important;
    }

    .reward-tabs .reward-img {
        width: 210px;
        height: 210px;
    }
</style>

<div id="reward">
    <a href="#rewardModal" class="reward-link modal-trigger btn-floating btn-medium waves-effect waves-light red">赏</a>

    <!-- Modal Structure -->
    <div id="rewardModal" class="modal">
        <div class="modal-content">
            <a class="close modal-close"><i class="fas fa-times"></i></a>
            <h4 class="reward-title">你的赏识是我前进的动力</h4>
            <div class="reward-content">
                <div class="reward-tabs">
                    <ul class="tabs row">
                        <li class="tab col s6 alipay-tab waves-effect waves-light"><a href="#alipay">支付宝</a></li>
                        <li class="tab col s6 wechat-tab waves-effect waves-light"><a href="#wechat">微 信</a></li>
                    </ul>
                    <div id="alipay">
                        <img src="/blog/medias/reward/alipay.jpg" class="reward-img" alt="支付宝打赏二维码">
                    </div>
                    <div id="wechat">
                        <img src="/blog/medias/reward/wechat.png" class="reward-img" alt="微信打赏二维码">
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<script>
    $(function () {
        $('.tabs').tabs();
    });
</script>

            
        </div>
    </div>

    

    

    

    
    <div class="livere-card card" data-aos="fade-up">
    <!-- 来必力City版安装代码 -->
    <div id="lv-container" class="card-content" data-id="city" data-uid="MTAyMC81NDQ2OS8zMDk0MA==">
        <script type="text/javascript">
            (function (d, s) {
                let j, e = d.getElementsByTagName(s)[0];
                if (typeof LivereTower === 'function') {
                    return;
                }

                j = d.createElement(s);
                j.src = 'https://cdn-city.livere.com/js/embed.dist.js';
                j.async = true;

                e.parentNode.insertBefore(j, e);
            })(document, 'script');
        </script>
        <noscript>为正常使用来必力评论功能请激活JavaScript。</noscript>
    </div>
    <!-- City版安装代码已完成 -->
</div>
    

    

    

    

    

    

<article id="prenext-posts" class="prev-next articles">
    <div class="row article-row">
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge left-badge text-color">
                <i class="fas fa-chevron-left"></i>&nbsp;上一篇</div>
            <div class="card">
                <a href="/blog/ThreadSynchronized/">
                    <div class="card-image">
                        
                        
                        <img src="/blog/medias/featureimages/46.png" class="responsive-img" alt="多线程同步与多线程通信本质（待完善）">
                        
                        <span class="card-title">多线程同步与多线程通信本质（待完善）</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            
                        
                    </div>
                    <div class="publish-info">
                        <span class="publish-date">
                            <i class="far fa-clock fa-fw icon-date"></i>2021-09-29
                        </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/blog/categories/Java/" class="post-category">
                                    Java
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/blog/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/">
                        <span class="chip bg-color">多线程</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge right-badge text-color">
                下一篇&nbsp;<i class="fas fa-chevron-right"></i>
            </div>
            <div class="card">
                <a href="/blog/ToolsMubu/">
                    <div class="card-image">
                        
                        
                        <img src="/blog/medias/featureimages/10.jpg" class="responsive-img" alt="分享一款思维导图工具-幕布">
                        
                        <span class="card-title">分享一款思维导图工具-幕布</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            
                        
                    </div>
                    <div class="publish-info">
                            <span class="publish-date">
                                <i class="far fa-clock fa-fw icon-date"></i>2021-09-24
                            </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/blog/categories/%E5%AE%9E%E7%94%A8%E5%B7%A5%E5%85%B7/" class="post-category">
                                    实用工具
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
            </div>
        </div>
        
    </div>
</article>

</div>



<!-- 代码块功能依赖 -->
<script type="text/javascript" src="/blog/libs/codeBlock/codeBlockFuction.js"></script>

<!-- 代码语言 -->

<script type="text/javascript" src="/blog/libs/codeBlock/codeLang.js"></script>


<!-- 代码块复制 -->

<script type="text/javascript" src="/blog/libs/codeBlock/codeCopy.js"></script>


<!-- 代码块收缩 -->

<script type="text/javascript" src="/blog/libs/codeBlock/codeShrink.js"></script>


    </div>
    <div id="toc-aside" class="expanded col l3 hide-on-med-and-down">
        <div class="toc-widget card" style="background-color: white;">
            <div class="toc-title"><i class="far fa-list-alt"></i>&nbsp;&nbsp;目录</div>
            <div id="toc-content"></div>
        </div>
    </div>
</div>

<!-- TOC 悬浮按钮. -->

<div id="floating-toc-btn" class="hide-on-med-and-down">
    <a class="btn-floating btn-large bg-color">
        <i class="fas fa-list-ul"></i>
    </a>
</div>


<script src="/blog/libs/tocbot/tocbot.min.js"></script>
<script>
    $(function () {
        tocbot.init({
            tocSelector: '#toc-content',
            contentSelector: '#articleContent',
            headingsOffset: -($(window).height() * 0.4 - 45),
            collapseDepth: Number('3'),
            headingSelector: 'h1, h2, h3, h4'
        });

        // modify the toc link href to support Chinese.
        let i = 0;
        let tocHeading = 'toc-heading-';
        $('#toc-content a').each(function () {
            $(this).attr('href', '#' + tocHeading + (++i));
        });

        // modify the heading title id to support Chinese.
        i = 0;
        $('#articleContent').children('h1, h2, h3, h4').each(function () {
            $(this).attr('id', tocHeading + (++i));
        });

        // Set scroll toc fixed.
        let tocHeight = parseInt($(window).height() * 0.4 - 64);
        let $tocWidget = $('.toc-widget');
        $(window).scroll(function () {
            let scroll = $(window).scrollTop();
            /* add post toc fixed. */
            if (scroll > tocHeight) {
                $tocWidget.addClass('toc-fixed');
            } else {
                $tocWidget.removeClass('toc-fixed');
            }
        });

        
        /* 修复文章卡片 div 的宽度. */
        let fixPostCardWidth = function (srcId, targetId) {
            let srcDiv = $('#' + srcId);
            if (srcDiv.length === 0) {
                return;
            }

            let w = srcDiv.width();
            if (w >= 450) {
                w = w + 21;
            } else if (w >= 350 && w < 450) {
                w = w + 18;
            } else if (w >= 300 && w < 350) {
                w = w + 16;
            } else {
                w = w + 14;
            }
            $('#' + targetId).width(w);
        };

        // 切换TOC目录展开收缩的相关操作.
        const expandedClass = 'expanded';
        let $tocAside = $('#toc-aside');
        let $mainContent = $('#main-content');
        $('#floating-toc-btn .btn-floating').click(function () {
            if ($tocAside.hasClass(expandedClass)) {
                $tocAside.removeClass(expandedClass).hide();
                $mainContent.removeClass('l9');
            } else {
                $tocAside.addClass(expandedClass).show();
                $mainContent.addClass('l9');
            }
            fixPostCardWidth('artDetail', 'prenext-posts');
        });
        
    });
</script>

    

</main>




    <footer class="page-footer bg-color">
    
        <link rel="stylesheet" href="/blog/libs/aplayer/APlayer.min.css">
<style>
    .aplayer .aplayer-lrc p {
        
        display: none;
        
        font-size: 12px;
        font-weight: 700;
        line-height: 16px !important;
    }

    .aplayer .aplayer-lrc p.aplayer-lrc-current {
        
        display: none;
        
        font-size: 15px;
        color: #42b983;
    }

    
    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body {
        left: -66px !important;
    }

    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body:hover {
        left: 0px !important;
    }

    
</style>
<div class="">
    
    <div class="row">
        <meting-js class="col l8 offset-l2 m10 offset-m1 s12"
                   server="netease"
                   type="playlist"
                   id="2821652960"
                   fixed='true'
                   autoplay='false'
                   theme='#42b983'
                   loop='all'
                   order='random'
                   preload='auto'
                   volume='0.7'
                   list-folded='true'
        >
        </meting-js>
    </div>
</div>

<script src="/blog/libs/aplayer/APlayer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/meting@2/dist/Meting.min.js"></script>

    

    <div class="container row center-align"
         style="margin-bottom: 15px !important;">
        <div class="col s12 m8 l8 copy-right">
            Copyright&nbsp;&copy;
            
                <span id="year">2021-2024</span>
            
            <a href="/blog/about" target="_blank">Xyq</a>
            |&nbsp;Powered by&nbsp;<a href="https://hexo.io/" target="_blank">Hexo</a>
            |&nbsp;Theme&nbsp;<a href="https://github.com/blinkfox/hexo-theme-matery" target="_blank">Matery</a>
            <br>
            
            
            
                
            
            
                <span id="busuanzi_container_site_pv">
                &nbsp;|&nbsp;<i class="far fa-eye"></i>&nbsp;总访问量:&nbsp;
                    <span id="busuanzi_value_site_pv" class="white-color"></span>
            </span>
            
            
                <span id="busuanzi_container_site_uv">
                &nbsp;|&nbsp;<i class="fas fa-users"></i>&nbsp;总访问人数:&nbsp;
                    <span id="busuanzi_value_site_uv" class="white-color"></span>
            </span>
            
            <br>

            <!-- 运行天数提醒. -->
            
                <span id="sitetime"> Loading ...</span>
                <script>
                    var calcSiteTime = function () {
                        var seconds = 1000;
                        var minutes = seconds * 60;
                        var hours = minutes * 60;
                        var days = hours * 24;
                        var years = days * 365;
                        var today = new Date();
                        var startYear = "2021";
                        var startMonth = "9";
                        var startDate = "23";
                        var startHour = "12";
                        var startMinute = "0";
                        var startSecond = "0";
                        var todayYear = today.getFullYear();
                        var todayMonth = today.getMonth() + 1;
                        var todayDate = today.getDate();
                        var todayHour = today.getHours();
                        var todayMinute = today.getMinutes();
                        var todaySecond = today.getSeconds();
                        var t1 = Date.UTC(startYear, startMonth, startDate, startHour, startMinute, startSecond);
                        var t2 = Date.UTC(todayYear, todayMonth, todayDate, todayHour, todayMinute, todaySecond);
                        var diff = t2 - t1;
                        var diffYears = Math.floor(diff / years);
                        var diffDays = Math.floor((diff / days) - diffYears * 365);

                        // 区分是否有年份.
                        var language = 'zh-CN';
                        if (startYear === String(todayYear)) {
                            document.getElementById("year").innerHTML = todayYear;
                            var daysTip = 'This site has been running for ' + diffDays + ' days';
                            if (language === 'zh-CN') {
                                daysTip = '本站已运行 ' + diffDays + ' 天';
                            } else if (language === 'zh-HK') {
                                daysTip = '本站已運行 ' + diffDays + ' 天';
                            }
                            document.getElementById("sitetime").innerHTML = daysTip;
                        } else {
                            document.getElementById("year").innerHTML = startYear + " - " + todayYear;
                            var yearsAndDaysTip = 'This site has been running for ' + diffYears + ' years and '
                                + diffDays + ' days';
                            if (language === 'zh-CN') {
                                yearsAndDaysTip = '本站已运行 ' + diffYears + ' 年 ' + diffDays + ' 天';
                            } else if (language === 'zh-HK') {
                                yearsAndDaysTip = '本站已運行 ' + diffYears + ' 年 ' + diffDays + ' 天';
                            }
                            document.getElementById("sitetime").innerHTML = yearsAndDaysTip;
                        }
                    }

                    calcSiteTime();
                </script>
            
            <br>
            
        </div>
        <div class="col s12 m4 l4 social-link social-statis">
    <a href="https://github.com/xiayunquan" class="tooltipped" target="_blank" data-tooltip="访问我的GitHub" data-position="top" data-delay="50">
        <i class="fab fa-github"></i>
    </a>



    <a href="mailto:xiayunquan@yeah.net" class="tooltipped" target="_blank" data-tooltip="邮件联系我" data-position="top" data-delay="50">
        <i class="fas fa-envelope-open"></i>
    </a>







    <a href="tencent://AddContact/?fromId=50&fromSubId=1&subcmd=all&uin=704006530" class="tooltipped" target="_blank" data-tooltip="QQ联系我: 704006530" data-position="top" data-delay="50">
        <i class="fab fa-qq"></i>
    </a>







</div>
    </div>
</footer>

<div class="progress-bar"></div>


    <!-- 搜索遮罩框 -->
<div id="searchModal" class="modal">
    <div class="modal-content">
        <div class="search-header">
            <span class="title"><i class="fas fa-search"></i>&nbsp;&nbsp;搜索</span>
            <input type="search" id="searchInput" name="s" placeholder="请输入搜索的关键字"
                   class="search-input">
        </div>
        <div id="searchResult"></div>
    </div>
</div>

<script type="text/javascript">
$(function () {
    var searchFunc = function (path, search_id, content_id) {
        'use strict';
        $.ajax({
            url: path,
            dataType: "xml",
            success: function (xmlResponse) {
                // get the contents from search data
                var datas = $("entry", xmlResponse).map(function () {
                    return {
                        title: $("title", this).text(),
                        content: $("content", this).text(),
                        url: $("url", this).text()
                    };
                }).get();
                var $input = document.getElementById(search_id);
                var $resultContent = document.getElementById(content_id);
                $input.addEventListener('input', function () {
                    var str = '<ul class=\"search-result-list\">';
                    var keywords = this.value.trim().toLowerCase().split(/[\s\-]+/);
                    $resultContent.innerHTML = "";
                    if (this.value.trim().length <= 0) {
                        return;
                    }
                    // perform local searching
                    datas.forEach(function (data) {
                        var isMatch = true;
                        var data_title = data.title.trim().toLowerCase();
                        var data_content = data.content.trim().replace(/<[^>]+>/g, "").toLowerCase();
                        var data_url = data.url;
                        data_url = data_url.indexOf('/') === 0 ? data.url : '/' + data_url;
                        var index_title = -1;
                        var index_content = -1;
                        var first_occur = -1;
                        // only match artiles with not empty titles and contents
                        if (data_title !== '' && data_content !== '') {
                            keywords.forEach(function (keyword, i) {
                                index_title = data_title.indexOf(keyword);
                                index_content = data_content.indexOf(keyword);
                                if (index_title < 0 && index_content < 0) {
                                    isMatch = false;
                                } else {
                                    if (index_content < 0) {
                                        index_content = 0;
                                    }
                                    if (i === 0) {
                                        first_occur = index_content;
                                    }
                                }
                            });
                        }
                        // show search results
                        if (isMatch) {
                            str += "<li><a href='" + data_url + "' class='search-result-title'>" + data_title + "</a>";
                            var content = data.content.trim().replace(/<[^>]+>/g, "");
                            if (first_occur >= 0) {
                                // cut out 100 characters
                                var start = first_occur - 20;
                                var end = first_occur + 80;
                                if (start < 0) {
                                    start = 0;
                                }
                                if (start === 0) {
                                    end = 100;
                                }
                                if (end > content.length) {
                                    end = content.length;
                                }
                                var match_content = content.substr(start, end);
                                // highlight all keywords
                                keywords.forEach(function (keyword) {
                                    var regS = new RegExp(keyword, "gi");
                                    match_content = match_content.replace(regS, "<em class=\"search-keyword\">" + keyword + "</em>");
                                });

                                str += "<p class=\"search-result\">" + match_content + "...</p>"
                            }
                            str += "</li>";
                        }
                    });
                    str += "</ul>";
                    $resultContent.innerHTML = str;
                });
            }
        });
    };

    searchFunc('/blog/search.xml', 'searchInput', 'searchResult');
});
</script>

    <!-- 回到顶部按钮 -->
<div id="backTop" class="top-scroll">
    <a class="btn-floating btn-large waves-effect waves-light" href="#!">
        <i class="fas fa-arrow-up"></i>
    </a>
</div>


    <script src="/blog/libs/materialize/materialize.min.js"></script>
    <script src="/blog/libs/masonry/masonry.pkgd.min.js"></script>
    <script src="/blog/libs/aos/aos.js"></script>
    <script src="/blog/libs/scrollprogress/scrollProgress.min.js"></script>
    <script src="/blog/libs/lightGallery/js/lightgallery-all.min.js"></script>
    <script src="/blog/js/matery.js"></script>

    <!-- Baidu Analytics -->

    <!-- Baidu Push -->

<script>
    (function () {
        var bp = document.createElement('script');
        var curProtocol = window.location.protocol.split(':')[0];
        if (curProtocol === 'https') {
            bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
        } else {
            bp.src = 'http://push.zhanzhang.baidu.com/push.js';
        }
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(bp, s);
    })();
</script>

    
    <script src="/blog/libs/others/clicklove.js" async="async"></script>
    
    
    <script async src="/blog/libs/others/busuanzi.pure.mini.js"></script>
    

    

    

    <!--腾讯兔小巢-->
    
    
    <script type="text/javascript" color="0,0,255"
        pointColor="0,0,255" opacity='0.7'
        zIndex="-1" count="99"
        src="/blog/libs/background/canvas-nest.js"></script>
    

    

    

    
    <script src="/blog/libs/instantpage/instantpage.js" type="module"></script>
    

</body>

</html>
